const { logger } = require('./logger');

/**
 * 菜单数据校验和规范化工具类
 * 用于Excel导入时的数据清洗、验证和规范化处理
 */
class MenuValidation {
  
  /**
   * 规范化字符串
   * 规则：trim → 全小写 → 连续空格压缩 → 去除非字母数字（保留空格/连字符/下划线）→ 空格替换为连字符
   * @param {string} str - 待规范化的字符串
   * @returns {string} 规范化后的字符串
   */
  static normalize(str) {
    if (!str || typeof str !== 'string') {
      return '';
    }
    
    return str
      .trim()                           // 去除首尾空格
      .toLowerCase()                    // 转为小写
      .replace(/\s+/g, ' ')            // 连续空格压缩为单个空格
      .replace(/[^a-z0-9\s\-_]/g, '')  // 只保留字母数字、空格、连字符、下划线
      .replace(/\s/g, '-')             // 空格替换为连字符
      .replace(/-+/g, '-')             // 连续连字符压缩为单个
      .replace(/^-+|-+$/g, '');        // 去除首尾连字符
  }
  
  /**
   * 清洗数据
   * 处理特殊字符、全角半角统一、智能引号替换、不可见字符清除
   * @param {string} str - 待清洗的字符串
   * @returns {string} 清洗后的字符串
   */
  static cleanData(str) {
    if (!str || typeof str !== 'string') {
      return '';
    }
    
    return str
      .trim()                                    // 去除首尾空格
      .replace(/[\u00A0\u2000-\u200B\u2028\u2029\uFEFF]/g, ' ') // 替换各种空白字符为普通空格
      .replace(/[\u201C\u201D]/g, '"')          // 智能双引号替换
      .replace(/[\u2018\u2019]/g, "'")          // 智能单引号替换
      .replace(/[\uFF01-\uFF5E]/g, (match) => { // 全角字符转半角
        return String.fromCharCode(match.charCodeAt(0) - 0xFEE0);
      })
      .replace(/[\u0000-\u001F\u007F-\u009F]/g, '') // 去除控制字符
      .replace(/\s+/g, ' ')                     // 连续空格压缩
      .trim();                                  // 再次去除首尾空格
  }
  
  /**
   * 解析布尔值
   * @param {any} value - 待解析的值
   * @returns {boolean} 解析后的布尔值
   */
  static parseBoolean(value) {
    if (typeof value === 'boolean') {
      return value;
    }
    
    if (typeof value === 'string') {
      const cleaned = value.trim().toLowerCase();
      return ['true', '1', 'yes', 'y', '是', '真', 'on', 'enabled'].includes(cleaned);
    }
    
    if (typeof value === 'number') {
      return value !== 0;
    }
    
    return false;
  }
  
  /**
   * 验证必填字段
   * @param {object} row - 数据行
   * @param {string[]} requiredFields - 必填字段列表
   * @returns {string[]} 错误信息数组
   */
  static validateRequiredFields(row, requiredFields = ['Name_English', 'Category']) {
    const errors = [];
    
    for (const field of requiredFields) {
      const value = this.cleanData(row[field]);
      if (!value) {
        errors.push(`${field} 为必填字段`);
      }
    }
    
    return errors;
  }
  
  /**
   * 验证字段长度
   * @param {object} row - 数据行
   * @param {object} lengthRules - 长度规则 {fieldName: maxLength}
   * @returns {string[]} 错误信息数组
   */
  static validateFieldLengths(row, lengthRules = {}) {
    const errors = [];
    const defaultRules = {
      'Name_English': 200,
      '菜品名称（中文）': 200,
      'Item Description（中文）': 5000,
      'Main Ingredients（中文）': 1000,
      'Category': 100,
      'Quantity Selection': 500
    };
    
    const rules = { ...defaultRules, ...lengthRules };
    
    for (const [field, maxLength] of Object.entries(rules)) {
      const value = this.cleanData(row[field]);
      if (value && value.length > maxLength) {
        errors.push(`${field} 长度不能超过 ${maxLength} 字符，当前长度: ${value.length}`);
      }
    }
    
    return errors;
  }
  
  /**
   * 验证价格字段
   * @param {object} row - 数据行
   * @returns {string[]} 错误信息数组
   */
  static validatePrice(row) {
    const errors = [];
    const priceValue = row['Price'];
    
    if (priceValue !== undefined && priceValue !== null && priceValue !== '') {
      const price = parseFloat(priceValue);
      
      if (isNaN(price)) {
        errors.push('Price 必须是有效的数字');
      } else if (price < 0) {
        errors.push('Price 不能为负数');
      } else if (price > 9999.99) {
        errors.push('Price 不能超过 9999.99');
      }
    }
    
    return errors;
  }
  
  /**
   * 验证枚举字段
   * @param {object} row - 数据行
   * @param {object} enumRules - 枚举规则 {fieldName: allowedValues[]}
   * @returns {string[]} 错误信息数组
   */
  static validateEnumFields(row, enumRules = {}) {
    const errors = [];
    
    for (const [field, allowedValues] of Object.entries(enumRules)) {
      const value = this.cleanData(row[field]);
      if (value && !allowedValues.includes(value)) {
        errors.push(`${field} 的值 "${value}" 不在允许的选项中: ${allowedValues.join(', ')}`);
      }
    }
    
    return errors;
  }
  
  /**
   * 验证字段格式
   * @param {object} row - 数据行
   * @returns {string[]} 错误信息数组
   */
  static validateFieldFormats(row) {
    const errors = [];
    
    // 验证英文名称不能仅包含符号
    const nameEn = this.cleanData(row['Name_English']);
    if (nameEn && !/[a-zA-Z0-9]/.test(nameEn)) {
      errors.push('Name_English 不能仅包含符号，必须包含字母或数字');
    }
    
    // 验证中文名称不能仅包含符号
    const nameCn = this.cleanData(row['菜品名称（中文）']);
    if (nameCn && !/[\u4e00-\u9fa5a-zA-Z0-9]/.test(nameCn)) {
      errors.push('菜品名称（中文） 不能仅包含符号，必须包含中文、字母或数字');
    }
    
    return errors;
  }
  
  /**
   * 验证跨字段逻辑
   * @param {object} row - 数据行
   * @returns {string[]} 错误信息数组
   */
  static validateCrossFieldLogic(row) {
    const errors = [];
    const price = parseFloat(row['Price']) || 0;
    const available = this.parseBoolean(row['Available']);
    
    // 如果价格为0或"Free"，检查是否有特殊说明
    if (price === 0 || String(row['Price']).toLowerCase().includes('free')) {
      const description = this.cleanData(row['Item Description（中文）']);
      if (!description.includes('免费') && !description.includes('赠送') && !description.includes('试吃')) {
        errors.push('免费商品需要在描述中说明免费原因（如：免费、赠送、试吃等）');
      }
    }
    
    // 如果商品不可用，价格应该大于0（避免误操作）
    if (!available && price === 0) {
      errors.push('不可用商品建议设置正常价格，避免误操作');
    }
    
    return errors;
  }
  
  /**
   * 检查重复数据
   * @param {object[]} data - 所有数据行
   * @param {number} currentIndex - 当前行索引
   * @returns {string[]} 错误信息数组
   */
  static checkDuplicates(data, currentIndex) {
    const errors = [];
    const currentRow = data[currentIndex];
    const currentNameEn = this.normalize(this.cleanData(currentRow['Name_English']));
    
    if (!currentNameEn) {
      return errors;
    }
    
    // 检查同一文件中的重复
    for (let i = 0; i < data.length; i++) {
      if (i === currentIndex) continue;
      
      const otherRow = data[i];
      const otherNameEn = this.normalize(this.cleanData(otherRow['Name_English']));
      
      if (currentNameEn === otherNameEn) {
        errors.push(`Name_English "${currentRow['Name_English']}" 在文件中重复（行 ${i + 2}）`);
        break;
      }
    }
    
    return errors;
  }
  
  /**
   * 验证肉类选择字段
   * @param {object} row - 数据行
   * @returns {string[]} 错误信息数组
   */
  static validateMeatSelections(row) {
    const errors = [];
    const meatFields = ['Meat Selection 1', 'Meat Selection 2', 'Meat Selection 3'];
    const validMeatOptions = [
      'Chicken', 'Beef', 'Fish', 'Seafood', 'Vegetarian', 'Vegan',
      '鸡肉', '牛肉', '鱼肉', '海鲜', '素食', '纯素'
    ];
    
    for (const field of meatFields) {
      const value = this.cleanData(row[field]);
      if (value && !validMeatOptions.some(option => 
        value.toLowerCase().includes(option.toLowerCase()) ||
        option.toLowerCase().includes(value.toLowerCase())
      )) {
        errors.push(`${field} "${value}" 不是有效的肉类选项`);
      }
    }
    
    return errors;
  }
  
  /**
   * 验证数量规格字段
   * @param {object} row - 数据行
   * @returns {string[]} 错误信息数组
   */
  static validateQuantitySelection(row) {
    const errors = [];
    const quantitySelection = this.cleanData(row['Quantity Selection']);
    
    if (quantitySelection) {
      // 检查是否包含数字和单位
      const hasNumber = /\d/.test(quantitySelection);
      const hasUnit = /(pieces?|pcs?|份|个|只|条|块|片|杯|碗|盘|serving|portion)/i.test(quantitySelection);
      
      if (!hasNumber) {
        errors.push('Quantity Selection 应包含数量信息（如：6 pieces, 10份）');
      }
      
      if (!hasUnit) {
        errors.push('Quantity Selection 应包含单位信息（如：pieces, 份, 个等）');
      }
    }
    
    return errors;
  }
  
  /**
   * 综合验证单行数据
   * @param {object} row - 数据行
   * @param {object[]} allData - 所有数据
   * @param {number} rowIndex - 行索引
   * @param {object} options - 验证选项
   * @returns {object} 验证结果 {isValid: boolean, errors: string[], warnings: string[]}
   */
  static validateRow(row, allData = [], rowIndex = 0, options = {}) {
    const errors = [];
    const warnings = [];
    
    try {
      // 必填字段验证
      errors.push(...this.validateRequiredFields(row, options.requiredFields));
      
      // 字段长度验证
      errors.push(...this.validateFieldLengths(row, options.lengthRules));
      
      // 价格验证
      errors.push(...this.validatePrice(row));
      
      // 字段格式验证
      errors.push(...this.validateFieldFormats(row));
      
      // 枚举字段验证
      if (options.enumRules) {
        errors.push(...this.validateEnumFields(row, options.enumRules));
      }
      
      // 跨字段逻辑验证
      warnings.push(...this.validateCrossFieldLogic(row));
      
      // 重复数据检查
      if (allData.length > 0) {
        errors.push(...this.checkDuplicates(allData, rowIndex));
      }
      
      // 肉类选择验证
      warnings.push(...this.validateMeatSelections(row));
      
      // 数量规格验证
      warnings.push(...this.validateQuantitySelection(row));
      
    } catch (error) {
      logger.error('数据验证过程中发生错误:', error);
      errors.push('数据验证过程中发生内部错误');
    }
    
    return {
      isValid: errors.length === 0,
      errors: errors.filter(Boolean),
      warnings: warnings.filter(Boolean)
    };
  }
  
  /**
   * 生成错误报告CSV内容
   * @param {object[]} errorRows - 错误行数据
   * @returns {string} CSV内容
   */
  static generateErrorReport(errorRows) {
    if (!errorRows || errorRows.length === 0) {
      return 'row_number,sheet,field,value,error_code,message\n';
    }
    
    const headers = 'row_number,sheet,field,value,error_code,message';
    const rows = errorRows.map(errorRow => {
      return errorRow.errors.map(error => {
        const field = error.field || 'unknown';
        const value = (error.value || '').toString().replace(/"/g, '""');
        const message = (error.message || '').toString().replace(/"/g, '""');
        const errorCode = error.code || 'VALIDATION_ERROR';
        
        return `${errorRow.rowNumber},"Sheet1","${field}","${value}","${errorCode}","${message}"`;
      }).join('\n');
    }).join('\n');
    
    return `${headers}\n${rows}`;
  }
}

module.exports = MenuValidation;